#include "ChatServer.h"

CChatServer::CChatServer()
{
    request_que_ = new CSafeQueue<CMsg>;
    response_que_ = new CSafeQueue<CMsg>;

    user_ = CUserManage::GetUserManage();

    work_thread_size_ = THREAD_SIZE;

    listen_fd_ = -1;

    epoll_fd_ = -1;
}

CChatServer::~CChatServer()
{
    delete request_que_;
    delete response_que_;   
    delete user_; 
}

//服务端初始化网络服务
bool CChatServer::Init()
{
    if(user_->Init() == false){
        printf("ChatServer Init false\n");
        return false;
    }

    listen_fd_ = socket(AF_INET, SOCK_STREAM, 0);
    if(listen_fd_ < 0){
        printf("ChatServer Init false\n");
        return false;
    }

    int opt = 1;
    // sockfd为需要端口复用的套接字
    setsockopt(listen_fd_, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt));

    //绑定地址信息
    struct sockaddr_in addr;
    addr.sin_port = htons(BIND_PORT);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("0.0.0.0");
    int ret = bind(listen_fd_, (sockaddr*)&addr, sizeof(addr));
    if(ret != 0){
        printf("ChatServer Init false\n");
        return false;
    }

    ret = listen(listen_fd_, 5);
    if(ret != 0){
        printf("listen init fail\n");
        return false;
    }

    epoll_fd_ = epoll_create(5);
    if(epoll_fd_ < 0){
        printf("epoll init fail\n");
        return false;
    }

    return true;
}

//启动各类线程
bool CChatServer::StartThread()
{
    //不需要保存，直接detach掉
    pthread_t pid;
    //启动发送线程
    int ret = pthread_create(&pid, NULL, SendStart, (void*)this);
    if(ret != 0){
        printf("Start Thread fail\n");
        return false;
    }

    //启动接收线程
    ret = pthread_create(&pid, NULL, RecvStart, (void*)this);
    if(ret != 0){
        printf("Start Thread fail\n");
        return false;
    }

    //启动工作线程
    for(int i = 0; i < THREAD_SIZE; ++i){
        ret = pthread_create(&pid, NULL, WorkStart, (void*)this);
        if(ret != 0){
            printf("Start Thread fail\n");
            return false;
        }
    }

    //main线程accept新链接套接字S
    while(1){
        int new_fd = accept(listen_fd_, NULL, NULL);
        struct epoll_event even;
        even.data.fd = new_fd;
        even.events = EPOLLIN;
        epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, new_fd, &even);
    }

    return true;
}

//接收线程
void* CChatServer::RecvStart(void* arg)
{
    pthread_detach(pthread_self());
    CChatServer* cs = (CChatServer*) arg;
    /*
        1. epoll_wait获取就绪事件
        2. 将元素放入请求队列
    */

    while(1){
        struct epoll_event arr[EPOLL_ARR_SIZE];
        int ret = epoll_wait(cs->epoll_fd_, arr, EPOLL_ARR_SIZE, -1);
        for(int i = 0; i < ret; ++i){
            char buf[10240] = {0};
            ssize_t r_recv = recv(arr[i].data.fd, buf, sizeof(buf) - 1, 0);
            if(r_recv < 0){
                continue;
            }else if(r_recv == 0){//客户端断开链接
                epoll_ctl(cs->epoll_fd_, EPOLL_CTL_DEL, arr[i].data.fd, NULL);
                close(arr[i].data.fd);
                continue;
            }
            //2. 添加服务端为链接分配的套接字
            CMsg ms;
            std::string body = buf;
            std::cout<<"recv: "<<std::endl;
            std::cout<<buf<<std::endl; 
            ms.ParseString(arr[i].data.fd, body);
            cs->request_que_->Push(ms);
        }
    }
}

//发送线程
void* CChatServer::SendStart(void* arg)
{
    pthread_detach(pthread_self());
    CChatServer* cs = (CChatServer*) arg;

    while(1){
        CMsg ms;
        cs->response_que_->Pop(ms);
        std::string msg;
        ms.GetString(msg);
        std::cout<<"send: "<<std::endl;
        std::cout<<msg<<std::endl;
        int ret = send(ms.socket_fd_, msg.c_str(), msg.size(), 0);
    }
}

//工作线程  
void* CChatServer::WorkStart(void* arg)
{
    pthread_detach(pthread_self());
    CChatServer* cs = (CChatServer*) arg;
    /*
        1.从请求队列中获取请求，然后解析处理
    */
    while(1){
        CMsg ms;
        cs->request_que_->Pop(ms);
        switch (ms.msg_type_)
        {
        case REGISTER://注册
            cs->RegisterHandle(ms);
            break;
        case  LOGIN://注册
            cs->LoginHandle(ms);
            break;
        case GETFRIEND:
            cs->GetFriendHandle(ms);
            break;
        case SEND_MSG:
            cs->ChatHandle(ms);
            break;
        case ADDFRIEND:
            cs->AddFriendHandle(ms);
            break;
        case ADDFRIEND_RESPONSE:
            cs->AddFriendResHandle(ms);
            break;
        case EXIT:
            cs->ExitHandle(ms);
            break;
        default:
            break;
        }
    }
}

//登录请求的处理
void CChatServer::LoginHandle(CMsg& ms)
{
    /*
        1. 反序列化得到passwd和tel
        2. 用户管理模块查询passwd和tel是否正确
        3. 登录成功返回自身的用户id
        4. 组织msg放入发送对列
    */
    std::string telnum = ms.msg_["telnum"].asString();
    std::string passwd = ms.msg_["passwd"].asString();
    //2.
    int ret = user_->LoginCheck(telnum, passwd, ms.socket_fd_);
    ms.Clear();
    ms.msg_type_ = LOGIN_RESPONSE;
    if(ret < 0){
        ms.response_ = LOGIN_FAIL;
    }else{
        ms.response_ = LOGIN_SUCCESS;
        ms.user_id_ = ret;
    }

    response_que_->Push(ms);
}

//注册处理
void CChatServer::RegisterHandle(CMsg& ms)
{
    /*
        0. 获取所需要的参数name，tel，passwd
        1. 用户管理模块进行注册
        2. 用户管理模块是否注册成功
        3. 组织msg，放入发送队列
    */

   //0.
    std::string nickname = ms.msg_["nickname"].asCString();
    std::string telnum = ms.msg_["telnum"].asCString();
    std::string passwd = ms.msg_["passwd"].asCString();

   //1. 用户模块
    ms.Clear();
    ms.msg_type_ = REGISTER_RESPONSE;
    int ret = user_->Register(nickname, telnum, passwd);
    if(ret < 0){
        ms.response_ = REGISTER_FAIL;
        response_que_->Push(ms);
        return;
    }

    ms.user_id_ = ret;
    ms.response_ = REGISTER_SUCCESS;
    response_que_->Push(ms);

}

//返回好友列表
void CChatServer::GetFriendHandle(CMsg& ms)
{
    /*
        1. 用户管理模块返回json数组
        2. 组织cmsg，将数组返回
    */
    Json::Value friend_arr;
    bool ret = user_->ReturnFriend(ms.user_id_, friend_arr);
    ms.Clear();
    ms.msg_type_ = GETFRIEND_RESPONSE;
    if(ret == false){
        ms.response_ = GETFRIEND_FAIL;
        response_que_->Push(ms);
        return;
    }

    ms.response_ = GETFRIEND_SUCCESS;
    ms.msg_["friends"] = friend_arr;

    response_que_->Push(ms);
}

//处理聊天
void CChatServer::ChatHandle(CMsg& ms)
{
    /*
        1. 检验双方是否在线
        2. 组织Msg将消息发送够用户
    */
    int send_id = ms.msg_["send_user"].asInt();
    int ret = user_->CheckUserStatus(ms.user_id_, send_id);
    ms.msg_type_ = SEND_MSG_RESPONSE;
    if(ret < 0){
        ms.response_ = SEND_MSG_FAIL;
        response_que_->Push(ms);
        return;
    }else{
        ms.response_ = SEND_MSG_SUCCESS;
    }

    response_que_->Push(ms);

    ms.socket_fd_ = ret;
    ms.msg_type_ = PUSH_MAG;
    response_que_->Push(ms);

}   

//处理添加好友
void CChatServer::AddFriendHandle(CMsg& ms)
{
    /*
        1. 用户管理查看添加是否在线
    */
    std::string telnum = ms.msg_["telnum"].asString();
    int ret = user_->CheckUserStatus(telnum);
    if(ret < 0)
        return;
    UserInfo ui;
    user_->GetUser(ms.user_id_, ui);
    ms.Clear();
    ms.socket_fd_ = ret;
    ms.msg_type_ = PUSH_ADDFRIEND;
    ms.msg_["nickname"] = ui.nickname_;
    ms.msg_["telnum"] = ui.telnum_;
    ms.msg_["user_id"] = ui.user_id_;

    response_que_->Push(ms);
}

//处理添加好友响应
void CChatServer::AddFriendResHandle(CMsg& ms)
{
    /*
        1. 看响应成功还是失败，失败直接不管
        2. 成功则在用户管理插入
        3. 回推
    */
    if(ms.response_ == ADDFRIEND_RESPONSE_FAIL)
        return;
    
    int user_id = ms.user_id_;
    int friend_id = ms.msg_["friend_id"].asInt();
    int ret = user_->RenewFriendInfo(user_id, friend_id);
    ms.Clear();
    ms.msg_type_ = ADDFRIEND_RESPONSE;
    ms.socket_fd_ = ret;
    ms.response_ = ADDFRIEND_RESPONSE_SUCCESS;
    UserInfo ui;
    user_->GetUser(user_id, ui);
    ms.msg_["nickname"] = ui.nickname_;
    ms.msg_["friend_id"] = ui.user_id_;

    response_que_->Push(ms);
}

//处理退出请求
void CChatServer::ExitHandle(CMsg& ms)
{
    user_->RenewUserStatus(ms.user_id_);
}
